C++ OpenCV实现物体尺寸测量示例详解

您所在的位置:网站首页 opencv定位 输出坐标案例 C++ OpenCV实现物体尺寸测量示例详解

C++ OpenCV实现物体尺寸测量示例详解

#C++ OpenCV实现物体尺寸测量示例详解| 来源: 网络整理| 查看: 265

目录前言一、图像透视矫正二、物体定位三、尺寸测量四、效果显示五、源码总结

前言

本文将使用OpenCV C++ 进行物体尺寸测量。具体来说就是先定位到待测物体的位置,然后测量物体的宽高。

一、图像透视矫正

原图如图所示。本案例的需求是测量图片中两张卡片的尺寸。首先,我们得定位到两张卡片的位置。第一步,我们首先得将白色A4纸切割出来,这样方便定位到两张卡片所在位置。这里用到的算法是图像透视矫正,具体可以参考OpenCV C++案例实战四《图像透视矫正》

//图像矫正 void getWarp(Mat src, Mat &Warp) { Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); Mat thresh; threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU); Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5)); Mat open; morphologyEx(thresh, open, MORPH_OPEN, kernel); vectorcontours; findContours(open, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); vectorconPoly(contours.size()); vectorsrcPts; //找到最大轮廓 int MaxIndex = 0; double Area = 0; for (int i = 0; i < contours.size(); i++) { double area = contourArea(contours[i]); if (area > Area) { Area = area; MaxIndex = i; } } //获取矩形四个角点 double peri = arcLength(contours[MaxIndex], true); approxPolyDP(contours[MaxIndex], conPoly[MaxIndex], 0.02*peri, true); srcPts = { conPoly[MaxIndex][0],conPoly[MaxIndex][1],conPoly[MaxIndex][2],conPoly[MaxIndex][3] }; int T_L, B_L, B_R, T_R; int width = src.cols / 2; int height = src.rows / 2; for (int i = 0; i < srcPts.size(); i++) { if (srcPts[i].x < width && srcPts[i].y < height) { T_L = i; } if (srcPts[i].x < width && srcPts[i].y > height) { B_L = i; } if (srcPts[i].x > width && srcPts[i].y > height) { B_R = i; } if (srcPts[i].x > width && srcPts[i].y < height) { T_R = i; } } double UpWidth = EuDis(srcPts[T_L], srcPts[T_R]); double DownWidth = EuDis(srcPts[B_L], srcPts[B_R]); double MaxWidth = max(UpWidth, DownWidth); double UpHeight = EuDis(srcPts[T_L], srcPts[B_L]); double DownHeight = EuDis(srcPts[T_R], srcPts[B_R]); double MaxHeight = max(UpHeight, DownHeight); //透视变换进行图像矫正 Point2f SrcAffinePts[4] = { Point2f(srcPts[T_L]),Point2f(srcPts[T_R]) ,Point2f(srcPts[B_R]) ,Point2f(srcPts[B_L]) }; Point2f DstAffinePts[4] = { Point2f(0,0),Point2f(MaxWidth,0),Point2f(MaxWidth,MaxHeight),Point2f(0,MaxHeight) }; Mat M = getPerspectiveTransform(SrcAffinePts, DstAffinePts); warpPerspective(src, Warp, M, Point(MaxWidth, MaxHeight)); }

效果如图所示。接下来,我们需要定位两张卡片所在位置,寻找特征。

二、物体定位 //获取物体坐标 void FindPts(Mat &Warp, vector&TargetPts) { Mat gray; cvtColor(Warp, gray, COLOR_BGR2GRAY); Mat thresh; threshold(gray, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU); Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); Mat open; morphologyEx(thresh, open, MORPH_OPEN, kernel); vectorcontours; findContours(open, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); vectorconPoly(contours.size()); //定位卡片四个角点 for (int i = 0; i < contours.size(); i++) { double area = contourArea(contours[i]); if (area > 1000) { double peri = arcLength(contours[i], true); approxPolyDP(contours[i], conPoly[i], 0.02*peri, true); vectortemp; temp = { conPoly[i][0],conPoly[i][1], conPoly[i][2], conPoly[i][3] }; TargetPts.push_back(temp); } } }

如图所示。通过上面代码段,我们已经定位出卡片的四个角点。接下来,只需根据角点位置就可以计算卡片的宽高了。

三、尺寸测量 //计算距离 void DrawAndCompute(Mat &Warp, vector&TargetPts) { for (int i = 0; i < TargetPts.size(); i++) { for (int j = 0; j < TargetPts[i].size(); j++) { //尺寸测量 Point PtA = Point(TargetPts[i][j]); Point PtB = Point(TargetPts[i][(j + 1) % TargetPts[i].size()]); double dis = round(EuDis(PtA, PtB) * 100) / 100; //效果显示 circle(Warp, TargetPts[i][j], 5, Scalar(0, 255, 0), -1); line(Warp, PtA, PtB, Scalar(0, 0, 255), 2); char text[20]; sprintf_s(text, "%.2f", dis); Point point = Point((PtA.x + PtB.x) / 2, (PtA.y + PtB.y) / 2); putText(Warp, text, point, FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 255), 2); } } }

四、效果显示

五、源码 #include #include using namespace std; using namespace cv; //欧式距离 double EuDis(Point pt1, Point pt2) { return sqrt((pt2.x - pt1.x)*(pt2.x - pt1.x) + (pt2.y - pt1.y)*(pt2.y - pt1.y)); } //图像矫正 void getWarp(Mat src, Mat &Warp) { Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); Mat thresh; threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU); Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5)); Mat open; morphologyEx(thresh, open, MORPH_OPEN, kernel); vectorcontours; findContours(open, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); vectorconPoly(contours.size()); vectorsrcPts; //找到最大轮廓 int MaxIndex = 0; double Area = 0; for (int i = 0; i < contours.size(); i++) { double area = contourArea(contours[i]); if (area > Area) { Area = area; MaxIndex = i; } } //获取矩形四个角点 double peri = arcLength(contours[MaxIndex], true); approxPolyDP(contours[MaxIndex], conPoly[MaxIndex], 0.02*peri, true); srcPts = { conPoly[MaxIndex][0],conPoly[MaxIndex][1],conPoly[MaxIndex][2],conPoly[MaxIndex][3] }; int T_L, B_L, B_R, T_R; int width = src.cols / 2; int height = src.rows / 2; for (int i = 0; i < srcPts.size(); i++) { if (srcPts[i].x < width && srcPts[i].y < height) { T_L = i; } if (srcPts[i].x < width && srcPts[i].y > height) { B_L = i; } if (srcPts[i].x > width && srcPts[i].y > height) { B_R = i; } if (srcPts[i].x > width && srcPts[i].y < height) { T_R = i; } } double UpWidth = EuDis(srcPts[T_L], srcPts[T_R]); double DownWidth = EuDis(srcPts[B_L], srcPts[B_R]); double MaxWidth = max(UpWidth, DownWidth); double UpHeight = EuDis(srcPts[T_L], srcPts[B_L]); double DownHeight = EuDis(srcPts[T_R], srcPts[B_R]); double MaxHeight = max(UpHeight, DownHeight); //透视变换进行图像矫正 Point2f SrcAffinePts[4] = { Point2f(srcPts[T_L]),Point2f(srcPts[T_R]) ,Point2f(srcPts[B_R]) ,Point2f(srcPts[B_L]) }; Point2f DstAffinePts[4] = { Point2f(0,0),Point2f(MaxWidth,0),Point2f(MaxWidth,MaxHeight),Point2f(0,MaxHeight) }; Mat M = getPerspectiveTransform(SrcAffinePts, DstAffinePts); warpPerspective(src, Warp, M, Point(MaxWidth, MaxHeight)); } //获取物体坐标 void FindPts(Mat &Warp, vector&TargetPts) { Mat gray; cvtColor(Warp, gray, COLOR_BGR2GRAY); Mat thresh; threshold(gray, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU); Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); Mat open; morphologyEx(thresh, open, MORPH_OPEN, kernel); vectorcontours; findContours(open, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); vectorconPoly(contours.size()); //定位卡片四个角点 for (int i = 0; i < contours.size(); i++) { double area = contourArea(contours[i]); if (area > 1000) { double peri = arcLength(contours[i], true); approxPolyDP(contours[i], conPoly[i], 0.02*peri, true); vectortemp; temp = { conPoly[i][0],conPoly[i][1], conPoly[i][2], conPoly[i][3] }; TargetPts.push_back(temp); } } } //计算距离 void DrawAndCompute(Mat &Warp, vector&TargetPts) { for (int i = 0; i < TargetPts.size(); i++) { for (int j = 0; j < TargetPts[i].size(); j++) { //尺寸测量 Point PtA = Point(TargetPts[i][j]); Point PtB = Point(TargetPts[i][(j + 1) % TargetPts[i].size()]); double dis = round(EuDis(PtA, PtB) * 100) / 100; //效果显示 circle(Warp, TargetPts[i][j], 5, Scalar(0, 255, 0), -1); line(Warp, PtA, PtB, Scalar(0, 0, 255), 2); char text[20]; sprintf_s(text, "%.2f", dis); Point point = Point((PtA.x + PtB.x) / 2, (PtA.y + PtB.y) / 2); putText(Warp, text, point, FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 255), 2); } } } int main() { Mat src = imread("src.jpg"); if (src.empty()) { cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3